`include "top.svh"
module Mtb_two_dual_fifo_pre;

localparam DATA_WIDTH = `DATA_WIDTH                         ;
localparam ADDR_WIDTH = `ADDR_WIDTH                         ;
localparam DATA_DEPTH = `DATA_DEPTH                         ;

reg                         i_clk                           ;
reg                         i_rst_n                         ;

// write signal
reg                         i_wr                            ;
reg       [DATA_WIDTH-1:0]  i_wdata                         ;
wire                        o_full                          ;
wire      [ADDR_WIDTH:0]    o_remain                        ;
// read signal
reg                         i_rd                            ;
wire      [DATA_WIDTH-1:0]  o_rdata                         ;
wire                        o_empty                         ;
wire      [ADDR_WIDTH:0]    o_use                           ;
// unusual
wire                        o_overflow                      ;
wire                        o_underflow                     ;

integer                     wr_en_value                     ;
integer                     wr_en_ratio                     ;

integer                     rd_en_value                     ;
integer                     rd_en_ratio                     ;

reg       [31:0]            wr_index                        ;
reg       [31:0]            rd_index                        ;
reg       [DATA_WIDTH-1:0]  fifo_mem [2**20-1:0]              ;

initial begin
  wr_en_ratio      = `FIFO_WR_EN_RATIO;
  rd_en_ratio      = `FIFO_RD_EN_RATIO;
  wr_en_value      = 0;
  rd_en_value      = 0;
end

initial begin
  i_clk   = 0;
  i_rst_n = 0;
  #50;
  i_rst_n = 1;
end
always #10 i_clk = ~i_clk;

//==========================================================
// wr                                             start//{{{
//==========================================================
always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    wr_en_value <= 'd0;
  end
  else begin
    wr_en_value <= {$random()} % 10;
  end
end

assign i_wr    = (~o_full) & (wr_en_ratio <= wr_en_value) & (wr_index < DATA_DEPTH*5);

assign i_wdata = fifo_mem[wr_index];
//==========================================================
// wr                                               end//}}}
//==========================================================

//==========================================================
// rd                                             start//{{{
//==========================================================
always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    rd_en_value <= 'd0;
  end
  else begin
    rd_en_value <= {$random()} % 10;
  end
end

assign i_rd    = (~o_empty) & (rd_en_ratio <= rd_en_value) & (rd_index < DATA_DEPTH*5);

//==========================================================
// rd                                               end//}}}
//==========================================================

//==========================================================
// dut                                            start//{{{
//==========================================================
Mtwo_dual_fifo_pre
#(
   .RAM_TYPE   ( "REG"      )
  ,.ADDR_WIDTH ( ADDR_WIDTH )
  ,.DATA_WIDTH ( DATA_WIDTH )
  ,.DATA_DEPTH ( DATA_DEPTH )
)
M_two_dual_fifo_pre
(
  // clk and rst
   .i_clk                   ( i_clk                         )
  ,.i_rst_n                 ( i_rst_n                       )
  // write signal
  ,.i_wr                    ( i_wr                          )
  ,.i_wdata                 ( i_wdata                       )
  ,.o_full                  ( o_full                        )
  ,.o_remain                ( o_remain                      )
  // read signal                         
  ,.i_rd                    ( i_rd                          )
  ,.o_rdata                 ( o_rdata                       )
  ,.o_empty                 ( o_empty                       )
  ,.o_use                   ( o_use                         )
  // unusual                             
  ,.o_overflow              ( o_overflow                    )
  ,.o_underflow             ( o_underflow                   )
);
//==========================================================
// dut                                              end//}}}
//==========================================================

//==========================================================
// check                                          start//{{{
//==========================================================
initial begin
  #1;
  $readmemh("fifo_data.hex",fifo_mem);
  $display("Info  : read mem file : fifo_data.hex");
end

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    wr_index <= 'd0;
  end
  else if(i_wr) begin
    wr_index <= wr_index + 'd1;
  end
end

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    rd_index <= 'd0;
  end
  else if(i_rd) begin
    rd_index <= rd_index + 'd1;
  end
end

always@(posedge i_clk) begin
  if(i_rd) begin
    if(o_rdata !== fifo_mem[rd_index]) begin
      $display("Error : data[%d] error", rd_index);
      $display("        expect  data : %x", fifo_mem[rd_index]);
      $display("        reality data : %x", o_rdata);
      #5;
      $finish();
    end
  end
end

always@(posedge i_clk) begin
  if(rd_index >= DATA_DEPTH*5) begin
    $display("                         ");
    $display("Info  : sim is ok !!!!!!!");
    $display("                         ");
    #5;
    $finish();
  end
end
//==========================================================
// check                                            end//}}}
//==========================================================

initial begin
  $fsdbDumpfile("tb.fsdb");
  $fsdbDumpvars;
  #100000000;
  $display("                         ");
  $display("Info  : time out !!!!!!!!");
  $display("                         ");
  $finish();
end

endmodule
